#include "table.h"
#include "../lib/rtl.h"
#include "../asm/int.h"

LPVOID IDTTable[INTR_ENTRY_CNT];
LPVOID SyscallTable[SYSCALL_CNT];

STATIC IDT_DESC IDT[IDT_DESC_CNT];

#define MAKE_IDT_DESCRIPTOR(lpIdtDesc, lpfnHandler, wSelector, bAttribute)     \
    lpIdtDesc->OffsetLow = (WORD)(DWORD_PTR)lpfnHandler;                       \
    lpIdtDesc->Selector = wSelector;                                           \
    lpIdtDesc->Count = 0;                                                      \
    lpIdtDesc->Attribute = bAttribute;                                         \
    lpIdtDesc->OffsetHigh = (WORD)((DWORD_PTR)lpfnHandler >> 16)

VOID InitIdt(VOID) {
    REG LPIDT_DESC lpIdtDesc;
    for (REG DWORD i = 0; i < INTR_ENTRY_CNT; i++) {
        lpIdtDesc = IDT + i;
        MAKE_IDT_DESCRIPTOR(lpIdtDesc, IntEntryTable[i], 0x0008,
                            INTR_P | INTR_DPL_0 | INTR_TYPE_INT32);
    }
    lpIdtDesc = IDT + SYSCALL_INTR;
    MAKE_IDT_DESCRIPTOR(lpIdtDesc, SyscallHandler, 0x0008,
                        INTR_P | INTR_DPL_3 | INTR_TYPE_TRAP32);
#pragma pack(1)
    struct {
        WORD wLimit;
        DWORD dwBase;
    } IDTPtr;
#pragma pack()
    IDTPtr.wLimit = (IDT_DESC_CNT << 3) - 1;
    IDTPtr.dwBase = (DWORD)(DWORD_PTR)IDT;
    __lidt(&IDTPtr.wLimit);
}
